// Copyright (C) ZHENG Zhong <heavyzheng nospam-at gmail D0T com>
//
// $Id: istring.hpp 229 2008-09-15 13:39:09Z heavyzheng $
//

#ifndef ZZHENG_UTILITY_ISTRING_HPP_20080602__
#define ZZHENG_UTILITY_ISTRING_HPP_20080602__

#include <zzheng/config.hpp>

#ifdef ZZHENG_MSVC
#  pragma warning(push)
#  pragma warning(disable: 4512)
#endif // ZZHENG_MSVC

#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/trim.hpp>

#ifdef ZZHENG_MSVC
#  pragma warning(pop)
#endif // ZZHENG_MSVC

#include <string>
#include <iostream>

namespace zzheng {

    //! \addtogroup utility zzheng.utility
    //! \{

    #ifndef DOXYGEN_SHOULD_SKIP_THIS

    namespace detail {

        template<typename Char, typename Traits>
        inline
        void trim_to_upper(std::basic_string<Char, Traits>& str) {
            boost::trim(str);
            boost::to_upper(str);
        }

    } // namespace zzheng::detail

    #endif // !DOXYGEN_SHOULD_SKIP_THIS

    ////////////////////////////////////////////////////////////////////////////////////////////////

    template<typename Char, typename Traits = std::char_traits<Char> > class basic_istring {

    public:

        typedef basic_istring<Char, Traits>      this_type;
        typedef std::basic_string<Char, Traits>  str_type;
        typedef typename str_type::value_type    value_type;
        typedef typename str_type::size_type     size_type;

    public:

        ////////////////////////////////////////////////////////////////////////////////////////////
        // constructors
        //

        explicit basic_istring(): str_() {
            // Do nothing.
        }

        basic_istring(const str_type& str): str_(str) {
            detail::trim_to_upper(str_);
        }

        basic_istring(const value_type* str): str_(str) {
            detail::trim_to_upper(str_);
        }

        // Use auto-generated copy constructor.
        // Use auto-generated copy assignment.
        // Use auto-generated destructor.


        ////////////////////////////////////////////////////////////////////////////////////////////
        // operators
        //

        this_type& operator=(const str_type& str) {
            str_ = str;
            detail::trim_to_upper(str_);
            return *this;
        }

        this_type& operator=(const value_type* str) {
            str_ = (str != 0 ? str : str_type());
            detail::trim_to_upper(str_);
            return *this;
        }

        ////////////////////////////////////////////////////////////////////////////////////////////
        // comparison operators
        //

        bool operator==(const this_type& rhs) const {
            return (str_ == rhs.str_);
        }

        bool operator<(const this_type& rhs) const {
            return (str_ < rhs.str_);
        }

        bool operator!=(const this_type& rhs) const {
            return !operator==(rhs);
        }

        bool operator>(const this_type& rhs) const {
            return (!operator==(rhs) && !operator<(rhs));
        }

        bool operator<=(const this_type& rhs) const {
            return (operator==(rhs) || operator<(rhs));
        }

        bool operator>=(const this_type& rhs) const {
            return !operator<(rhs);
        }

        ////////////////////////////////////////////////////////////////////////////////////////////
        // public member functions
        //

        void swap(this_type& rhs) {
            str_.swap(rhs.str_);
        }

        bool empty() const {
            return str_.empty();
        }

        size_type size() const {
            return str_.size();
        }

        const str_type& str() const {
            return str_;
        }

        const value_type* c_str() const {
            return str_.c_str();
        }

        void clear() {
            str_.clear();
        }

    private:

        str_type str_;

    }; // class basic_istring

    ////////////////////////////////////////////////////////////////////////////////////////////////

    template<typename Char, typename Traits>
    inline
    std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& is,
                                                 basic_istring<Char, Traits>& istr) {
        typename basic_istring<Char, Traits>::str_type str;
        is >> str;
        istr = str;
        return is;
    }

    template<typename Char, typename Traits>
    inline
    std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,
                                                 const basic_istring<Char, Traits>& istr) {
        return (os << istr.str());
    }
    
    ////////////////////////////////////////////////////////////////////////////////////////////////

    typedef basic_istring<char> istring;

    //! \} end group utility

} // namespace zzheng

#endif // ZZHENG_UTILITY_ISTRING_HPP_20080602__



